import { Injectable, Req, ExecutionContext } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { Like, Repository, EntityManager } from 'typeorm';
import { instanceToPlain, plainToInstance } from 'class-transformer';
import { genSalt } from 'bcryptjs';

import { SupplierEntity } from './entities/supplier.entity'

import { ResultData } from '../common/utils/result'
import { AppHttpCode } from '../common/enums/code.enum'

import { CreateSupplierDto } from './dto/create-supplier.dto'
import { UpdateSupplierDto } from './dto/update-supplier.dto'
import { FindSupplierListDto } from './dto/find-supplier-list.dto'

import { OperalogService } from 'src/system/operalog/operalog.service'

@Injectable()
export class SupplierService {
  constructor(
    @InjectRepository(SupplierEntity)
    private readonly supplierRepo: Repository<SupplierEntity>,
    @InjectEntityManager()
    private readonly supplierManager: EntityManager,
    private readonly operalogService: OperalogService,
  ) {}

  async findOneById(id: string): Promise<SupplierEntity> {
    let supplier = await this.supplierRepo.findOne({ where: { id } })
    supplier = plainToInstance(SupplierEntity, { ...supplier }, { enableImplicitConversion: true })
    return supplier
  }

  /** 创建供应商 */
  async create(createSupplierDto: CreateSupplierDto, account: String, ip: String) {
    // 防止重复创建
    const salt = await genSalt()
    const supplier = plainToInstance(SupplierEntity, { salt, ...createSupplierDto }, { ignoreDecorators: true })
    const result = await this.supplierManager.transaction(async (transactionalEntityManager) => {
      return await transactionalEntityManager.save<SupplierEntity>(supplier)
    })

    if (!result) ResultData.fail(AppHttpCode.SERVICE_ERROR, '创建失败，请稍后重试');

    /** 创建供应商成功后插入操作日志 */
    if (ip.indexOf('::ffff:') !== -1) {
      ip = ip.substring(7)
    }
    this.operalogService.create({
      systemMenu: '供应商',
      operaModule: `添加供应商 -【${createSupplierDto.name}】`,
      operaName: account,
      operaIp: ip,
      status: 1
    })
    return ResultData.ok(instanceToPlain(result));
  }

  /** 查询供应商分页查询 */
  async findList(dto: FindSupplierListDto) {
    const { page, size, name, userName, phone } = dto;
    const where = {
      ...(userName ? { userName: Like(`%${userName}%`) } : null),
      ...(name ? { name: Like(`%${name}%`) } : null),
      ...(phone ? { phone: Like(`%${phone}%`) } : null),
      isDelete: 1
    }
    const supplier = await this.supplierRepo.findAndCount({
      where,
      order: { id: 'DESC' },
      skip: size * (page - 1),
      take: size,
    })
    return ResultData.ok({ list: instanceToPlain(supplier[0]), total: supplier[1] })
  }

  /** 查询供应商信息 */
  async findOne(id: string) {
    const supplier = await this.findOneById(id)
    if (!supplier) return ResultData.fail(AppHttpCode.USER_NOT_FOUND, '该供应商不存在或已删除')
    return ResultData.ok(instanceToPlain(supplier))
  }

  /** 更新供应商 */
  async update(updateSupplierDto: UpdateSupplierDto, account: String, ip: String) {
    /** 查询是否存在 */
    const existing = await this.findOneById(updateSupplierDto.id)
    if (!existing) return ResultData.fail(AppHttpCode.USER_NOT_FOUND, '该供应商不存在或已删除');
    /** 更新供应商 */
    const supplierInfo = instanceToPlain(updateSupplierDto)
    const { affected } = await this.supplierManager.transaction(async (transactionalEntityManager) => {
      return await transactionalEntityManager.update<SupplierEntity>(SupplierEntity, updateSupplierDto.id, supplierInfo)
    })

    if (!affected) ResultData.fail(AppHttpCode.SERVICE_ERROR, '更新失败，请稍后重试');
    /** 更新供应商成功后插入操作日志 */
    if (ip.indexOf('::ffff:') !== -1) {
      ip = ip.substring(7)
    }
    this.operalogService.create({
      systemMenu: '供应商',
      operaModule: `更新供应商 -【${updateSupplierDto.name}】`,
      operaName: account,
      operaIp: ip,
      status: 1
    })
    return ResultData.ok();
  }

  /** 逻辑删除供应商 */
  async updateDelete(supplierId: string, isDelete: 0 | 1, account: String, ip: String): Promise<ResultData> {
    /** 查询当前伙伴是否存在 */
    const existing = await this.findOneById(supplierId)
    if (!existing) ResultData.fail(AppHttpCode.USER_NOT_FOUND, '当前供应商不存在或已删除')
    /** 逻辑删除供应商 */
    const { affected } = await this.supplierManager.transaction(async (transactionalEntityManager) => {
      return await transactionalEntityManager.update<SupplierEntity>(SupplierEntity, supplierId, { id: supplierId, isDelete })
    })
    if (!affected) ResultData.fail(AppHttpCode.SERVICE_ERROR, '删除失败，请稍后尝试');

    /** 逻辑删除供应商成功后插入操作日志 */
    if (ip.indexOf('::ffff:') !== -1) {
      ip = ip.substring(7)
    }
    this.operalogService.create({
      systemMenu: '供应商',
      operaModule: `删除供应商 -【${existing.name}】`,
      operaName: account,
      operaIp: ip,
      status: 1
    })
    return ResultData.ok()
  }
}
